#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>

#ifndef WIN32
#include <sys/ioctl.h>
#include <termios.h>
#endif

void
progress_bar(uint32_t part, uint32_t total)
{
#define MINWIDTH 80
	static struct timeval now, lp = { 0 };
	char *units[] = { "Bytes", "KBytes", "MBytes", "GBytes" };
	int unit;
	char buf[MINWIDTH];
	int pct = ((float) part / total) * 100;
	int cnt;
	float t, p;
	int hlen, tlen, plen;
	int width = MINWIDTH;
#ifndef WIN32
	struct winsize ws;
#endif

	gettimeofday(&now, NULL);
	if (part < total) {
		if (now.tv_sec - lp.tv_sec == 0 &&
		    now.tv_usec - lp.tv_usec < 100000)
			return;
	}
	gettimeofday(&lp, NULL);

#ifndef WIN32
	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
		width = ws.ws_col;
#endif

	t = total;
	p = part;
	for (unit = 0; unit < 3 && t > 1024; ++unit) {
		t /= 1024;
		p /= 1024;
	}
	tlen = snprintf(buf, sizeof(buf), "] % 3d%% (%.01f/%.01f %s) ",
	    100, t, t, units[unit]);
	hlen = snprintf(buf, sizeof(buf), "Progress: [");
	plen = width - hlen - 35;
	if (width - hlen - tlen < plen)
		plen = width - hlen - tlen;
	else
		tlen = 35;

	printf("\r");
	printf("%s", buf);
	cnt = floor(plen * pct / 100.0); 
	while (cnt-- > 0)
		putchar('=');
	cnt = plen - floor(plen * pct / 100.0);
	while (cnt-- > 0)
		putchar(' ');
	if (t != p)
		printf("] % 3d%% (%.01f/%.01f %s) ", pct, p, t,
		    units[unit]);
	else {
		printf("] Complete. ");
		cnt = tlen - strlen("] Complete. ");
		while (cnt-- > 0)
			putchar(' ');
		printf("\n");
	}

	fflush(stdout);
}
